/*
    nspire-gamekit - a simple homebrew game framework
    Copyright (C) 2011  Daniel Tang

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <os.h>
#include "screen.h"
#include "nimg.h"
#include "gameloop.h"
#include "autorelease.h"
#include "text.h"
#include "optimized.h"
#include "objects.h"   
#include "file.h"
#include "random.h"
#include "timer.h"
#include "collision.h"

#define GAME_FPS 30

#define gravity 0.5;

/* Yeah, this would be a good time to tie in some OOP */

struct game_obj {
    enum {
        mountain
    } type;
};

static nspire_screen_buffer* frameBuffer = NULL;
static nspire_screen_buffer* plane = NULL;
static nspire_screen_buffer* mount = NULL;
static nspire_screen_buffer* title = NULL;

static int titlePosition = 0;
static int planePosition = 40;
static float planeVelocity = 0;
static float fpsCount = 0;
static char bammed = 0;
static int score = 0;

void bam(void*);

int update(void* userdata) {
    (void)userdata;
    if (isKeyPressed(KEY_NSPIRE_5)) return 1;
    if (isKeyPressed(KEY_NSPIRE_SHIFT)) gameLoopSetFps(1000);
    if (isKeyPressed(KEY_NSPIRE_CTRL)) gameLoopSetFps(GAME_FPS);
    
    if (!bammed) {
        if (isKeyPressed(KEY_NSPIRE_2)) {
            planeVelocity -= gravity;
        }else{
            planeVelocity += gravity;
        }
        planePosition += planeVelocity;
    
        if (planePosition > SCREEN_HEIGHT || planePosition < -screenBufferHeight(plane)) {
            bam(NULL);
        }
        titlePosition-=1;
        if (titlePosition < -320) {
            titlePosition = 320;
        }
        score++;
    }
    gameTimerTick();
    
    
    return 0;
}

void fps(void* userdata, float f) {
    (void)userdata;
    fpsCount = f;
}

void draw(void* userdata) {
    (void)userdata;
    screenBufferDrawScreen(titlePosition,0,title,frameBuffer);
    
    screenBufferDrawScreen((titlePosition<0) ? titlePosition+320 : titlePosition-320,0,title,frameBuffer);
    
    /*screenBufferDrawScreen(mountPosition,20,mount,frameBuffer);
    screenBufferDrawScreen(mountPosition-100,20,mount,frameBuffer);
    screenBufferDrawScreen(mountPosition-200,20,mount,frameBuffer);*/
    gameObjectSendUpdateEvent();
    
    
    char buffer[500];
    sprintf(buffer, "FPS: %d.%02d  SCORE: %d", (int)fpsCount, (int)((fpsCount-(int)fpsCount)*100), score);
    screenBufferDrawString(10,10,buffer,0xF0,2,frameBuffer);
    
    if (bammed) screenBufferDrawString(120,60,"GAME OVER",0xF0,2,frameBuffer);
    else    screenBufferDrawScreen(60,planePosition,plane,frameBuffer);
    
    screenBufferFlushToScreen(frameBuffer);
    //screenBufferFlushToScreen(frameBuffer);
    
    
    /*Smarter way to clear the screen...*/
    //screenBufferDrawScreen(60,planePosition,planeMask,frameBuffer);
}

void finish(void* userdata) {
    (void)userdata;
    /*screenBufferDestroy(frameBuffer);
    screenBufferDestroy(mount);
    screenBufferDestroy(plane);
    screenBufferDestroy(planeMask);
    screenBufferDestroy(title);*/
    
    printf("Alloc'd memory blocks before draining: %d\n", gameMemCount());
    gameAutoDrain();
    printf("Alloc'd memory blocks after draining: %d\n", gameMemCount());
}
void bam(void* userdata) {
    (void)userdata; //Kill gcc warning
    planePosition = 40;
            planeVelocity = 0;
            score = 0;
    bammed = 0;
}
void obj_update(nspire_game_obj* self) {
    if (!bammed) {
        self->x -= 1;
        if (self->x < -160) {
            self->x = 320 + (((unsigned)gameRandomInteger()) % 160);
            self->y = 80 + (((unsigned)gameRandomInteger()) % 160);
        }
        if (gameCheckCollision(self->x, self->y, self->sprite, 
                        60, planePosition, plane)) {
            bammed = 1;
            gameTimerRunAfter(3, bam, NULL);
        }
        
    }
    
    screenBufferDrawScreen(self->x,self->y,mount,frameBuffer);
}
void hookDataAbortException();
unsigned int gameSha256(int*block512);

int main(int argc, char *argv[]) {
    (void)argc; //Stops silly warning from gcc
    gameSetCurrentDir(argv[0]);
    hookDataAbortException();
    frameBuffer = screenBufferAlloc(320, 240);
    plane = screenBufferFromFile("plane.tns");
    mount = screenBufferFromFile("mount.tns");
    title = screenBufferFromFile("header.tns");
    
    if (!frameBuffer) { printf("Failed to alloc\n"); return 0; }
    if (!plane) { finish(NULL); printf("Failed to load from file\n"); return 0; }
    if (!mount) { finish(NULL); printf("Failed to load from file\n"); return 0; }
    
    screenBufferClear(255, frameBuffer);
    
    int i;
    nspire_game_obj* obj;
    for (i=0; i<5; i++) {
        obj = gameObjectNew();
        if (obj) {
            obj->x = i*100;
            obj->y = 80 + (((unsigned)gameRandomInteger()) % 160);
            obj->sprite = mount;
            obj->events.update = obj_update;
            gameObjectAdd(obj);
        }
        
    }
    
    game_event_funcs_t funcs;
    funcs.init = NULL;
    funcs.update = update;
    funcs.draw = draw;
    funcs.finish = finish;
    funcs.fps = fps;
    
    gameLoopRun(&funcs, NULL, GAME_FPS);
    
    gameRestoreCurrentDir();
    return 0;
}
